home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume26 / tclx / part21 < prev    next >
Encoding:
Text File  |  1991-11-19  |  30.4 KB  |  1,103 lines

  1. Newsgroups: comp.sources.misc
  2. From: karl@sugar.neosoft.com (Karl Lehenbauer)
  3. Subject:  v26i021:  tclx - extensions and on-line help for tcl 6.1, Part21/23
  4. Message-ID: <1991Nov19.135808.1619@sparky.imd.sterling.com>
  5. X-Md4-Signature: 720cc57cee5f4f49a4f936f2b16ca5fb
  6. Date: Tue, 19 Nov 1991 13:58:08 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: karl@sugar.neosoft.com (Karl Lehenbauer)
  10. Posting-number: Volume 26, Issue 21
  11. Archive-name: tclx/part21
  12. Environment: UNIX
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then unpack
  16. # it by saving it into a file and typing "sh file".  To overwrite existing
  17. # files, type "sh file -c".  You can also feed this as standard input via
  18. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  19. # will see the following message at the end:
  20. #        "End of archive 21 (of 23)."
  21. # Contents:  extended/ucbsrc/tclBasic.c
  22. # Wrapped by karl@one on Wed Nov 13 21:50:33 1991
  23. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  24. if test -f 'extended/ucbsrc/tclBasic.c' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'extended/ucbsrc/tclBasic.c'\"
  26. else
  27. echo shar: Extracting \"'extended/ucbsrc/tclBasic.c'\" \(27787 characters\)
  28. sed "s/^X//" >'extended/ucbsrc/tclBasic.c' <<'END_OF_FILE'
  29. X/* 
  30. X * tclBasic.c --
  31. X *
  32. X *    Contains the basic facilities for TCL command interpretation,
  33. X *    including interpreter creation and deletion, command creation
  34. X *    and deletion, and command parsing and execution.
  35. X *
  36. X * Copyright 1987-1991 Regents of the University of California
  37. X * Permission to use, copy, modify, and distribute this
  38. X * software and its documentation for any purpose and without
  39. X * fee is hereby granted, provided that the above copyright
  40. X * notice appear in all copies.  The University of California
  41. X * makes no representations about the suitability of this
  42. X * software for any purpose.  It is provided "as is" without
  43. X * express or implied warranty.
  44. X */
  45. X/*
  46. X * This file was modified to incorporate signal handling for Extended Tcl.
  47. X */
  48. X
  49. X#ifndef lint
  50. Xstatic char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclBasic.c,v 1.128 91/10/31 16:41:13 ouster Exp $ SPRITE (Berkeley)";
  51. X#endif
  52. X
  53. X#include "tclInt.h"
  54. X
  55. X/*
  56. X * The following structure defines all of the commands in the Tcl core,
  57. X * and the C procedures that execute them.
  58. X */
  59. X
  60. Xtypedef struct {
  61. X    char *name;            /* Name of command. */
  62. X    Tcl_CmdProc *proc;        /* Procedure that executes command. */
  63. X} CmdInfo;
  64. X
  65. X/*
  66. X * Built-in commands, and the procedures associated with them:
  67. X */
  68. X
  69. Xstatic CmdInfo builtInCmds[] = {
  70. X    /*
  71. X     * Commands in the generic core:
  72. X     */
  73. X
  74. X    {"append",        Tcl_AppendCmd},
  75. X    {"array",        Tcl_ArrayCmd},
  76. X    {"break",        Tcl_BreakCmd},
  77. X    {"case",        Tcl_CaseCmd},
  78. X    {"catch",        Tcl_CatchCmd},
  79. X    {"concat",        Tcl_ConcatCmd},
  80. X    {"continue",    Tcl_ContinueCmd},
  81. X    {"error",        Tcl_ErrorCmd},
  82. X    {"eval",        Tcl_EvalCmd},
  83. X    {"expr",        Tcl_ExprCmd},
  84. X    {"for",        Tcl_ForCmd},
  85. X    {"foreach",        Tcl_ForeachCmd},
  86. X    {"format",        Tcl_FormatCmd},
  87. X    {"global",        Tcl_GlobalCmd},
  88. X    {"if",        Tcl_IfCmd},
  89. X    {"incr",        Tcl_IncrCmd},
  90. X    {"info",        Tcl_InfoCmd},
  91. X    {"join",        Tcl_JoinCmd},
  92. X    {"lappend",        Tcl_LappendCmd},
  93. X    {"lindex",        Tcl_LindexCmd},
  94. X    {"linsert",        Tcl_LinsertCmd},
  95. X    {"list",        Tcl_ListCmd},
  96. X    {"llength",        Tcl_LlengthCmd},
  97. X    {"lrange",        Tcl_LrangeCmd},
  98. X    {"lreplace",    Tcl_LreplaceCmd},
  99. X    {"lsearch",        Tcl_LsearchCmd},
  100. X    {"lsort",        Tcl_LsortCmd},
  101. X    {"proc",        Tcl_ProcCmd},
  102. X    {"regexp",        Tcl_RegexpCmd},
  103. X    {"regsub",        Tcl_RegsubCmd},
  104. X    {"rename",        Tcl_RenameCmd},
  105. X    {"return",        Tcl_ReturnCmd},
  106. X    {"scan",        Tcl_ScanCmd},
  107. X    {"set",        Tcl_SetCmd},
  108. X    {"split",        Tcl_SplitCmd},
  109. X    {"string",        Tcl_StringCmd},
  110. X    {"trace",        Tcl_TraceCmd},
  111. X    {"unset",        Tcl_UnsetCmd},
  112. X    {"uplevel",        Tcl_UplevelCmd},
  113. X    {"upvar",        Tcl_UpvarCmd},
  114. X    {"while",        Tcl_WhileCmd},
  115. X
  116. X    /*
  117. X     * Commands in the UNIX core:
  118. X     */
  119. X
  120. X#ifndef TCL_GENERIC_ONLY
  121. X    {"cd",        Tcl_CdCmd},
  122. X    {"close",        Tcl_CloseCmd},
  123. X    {"eof",        Tcl_EofCmd},
  124. X    {"exec",        Tcl_ExecCmd},
  125. X    {"exit",        Tcl_ExitCmd},
  126. X    {"file",        Tcl_FileCmd},
  127. X    {"flush",        Tcl_FlushCmd},
  128. X    {"gets",        Tcl_GetsCmd},
  129. X    {"glob",        Tcl_GlobCmd},
  130. X    {"open",        Tcl_OpenCmd},
  131. X    {"puts",        Tcl_PutsCmd},
  132. X    {"pwd",        Tcl_PwdCmd},
  133. X    {"read",        Tcl_ReadCmd},
  134. X    {"seek",        Tcl_SeekCmd},
  135. X    {"source",        Tcl_SourceCmd},
  136. X    {"tell",        Tcl_TellCmd},
  137. X    {"time",        Tcl_TimeCmd},
  138. X#endif /* TCL_GENERIC_ONLY */
  139. X    {NULL,        (Tcl_CmdProc *) NULL}
  140. X};
  141. X
  142. X/*
  143. X *----------------------------------------------------------------------
  144. X *
  145. X * Tcl_CreateInterp --
  146. X *
  147. X *    Create a new TCL command interpreter.
  148. X *
  149. X * Results:
  150. X *    The return value is a token for the interpreter, which may be
  151. X *    used in calls to procedures like Tcl_CreateCmd, Tcl_Eval, or
  152. X *    Tcl_DeleteInterp.
  153. X *
  154. X * Side effects:
  155. X *    The command interpreter is initialized with an empty variable
  156. X *    table and the built-in commands.
  157. X *
  158. X *----------------------------------------------------------------------
  159. X */
  160. X
  161. XTcl_Interp *
  162. XTcl_CreateInterp()
  163. X{
  164. X    register Interp *iPtr;
  165. X    register Command *cmdPtr;
  166. X    register CmdInfo *cmdInfoPtr;
  167. X    int i;
  168. X
  169. X    iPtr = (Interp *) ckalloc(sizeof(Interp));
  170. X    iPtr->result = iPtr->resultSpace;
  171. X    iPtr->freeProc = 0;
  172. X    iPtr->errorLine = 0;
  173. X    Tcl_InitHashTable(&iPtr->commandTable, TCL_STRING_KEYS);
  174. X    Tcl_InitHashTable(&iPtr->globalTable, TCL_STRING_KEYS);
  175. X    iPtr->numLevels = 0;
  176. X    iPtr->framePtr = NULL;
  177. X    iPtr->varFramePtr = NULL;
  178. X    iPtr->activeTracePtr = NULL;
  179. X    iPtr->numEvents = 0;
  180. X    iPtr->events = NULL;
  181. X    iPtr->curEvent = 0;
  182. X    iPtr->curEventNum = 0;
  183. X    iPtr->revPtr = NULL;
  184. X    iPtr->historyFirst = NULL;
  185. X    iPtr->revDisables = 1;
  186. X    iPtr->evalFirst = iPtr->evalLast = NULL;
  187. X    iPtr->appendResult = NULL;
  188. X    iPtr->appendAvl = 0;
  189. X    iPtr->appendUsed = 0;
  190. X    iPtr->numFiles = 0;
  191. X    iPtr->filePtrArray = NULL;
  192. X    for (i = 0; i < NUM_REGEXPS; i++) {
  193. X    iPtr->patterns[i] = NULL;
  194. X    iPtr->regexps[i] = NULL;
  195. X    }
  196. X    iPtr->cmdCount = 0;
  197. X    iPtr->noEval = 0;
  198. X    iPtr->scriptFile = NULL;
  199. X    iPtr->flags = 0;
  200. X    iPtr->tracePtr = NULL;
  201. X    iPtr->resultSpace[0] = 0;
  202. X
  203. X    /*
  204. X     * Create the built-in commands.  Do it here, rather than calling
  205. X     * Tcl_CreateCommand, because it's faster (there's no need to
  206. X     * check for a pre-existing command by the same name).
  207. X     */
  208. X
  209. X    for (cmdInfoPtr = builtInCmds; cmdInfoPtr->name != NULL; cmdInfoPtr++) {
  210. X    int new;
  211. X    Tcl_HashEntry *hPtr;
  212. X
  213. X    hPtr = Tcl_CreateHashEntry(&iPtr->commandTable,
  214. X        cmdInfoPtr->name, &new);
  215. X    if (new) {
  216. X        cmdPtr = (Command *) ckalloc(sizeof(Command));
  217. X        cmdPtr->proc = cmdInfoPtr->proc;
  218. X        cmdPtr->clientData = (ClientData) NULL;
  219. X        cmdPtr->deleteProc = NULL;
  220. X        Tcl_SetHashValue(hPtr, cmdPtr);
  221. X    }
  222. X    }
  223. X
  224. X#ifndef TCL_GENERIC_ONLY
  225. X    TclSetupEnv((Tcl_Interp *) iPtr);
  226. X#endif
  227. X
  228. X    return (Tcl_Interp *) iPtr;
  229. X}
  230. X
  231. X/*
  232. X *----------------------------------------------------------------------
  233. X *
  234. X * Tcl_DeleteInterp --
  235. X *
  236. X *    Delete an interpreter and free up all of the resources associated
  237. X *    with it.
  238. X *
  239. X * Results:
  240. X *    None.
  241. X *
  242. X * Side effects:
  243. X *    The interpreter is destroyed.  The caller should never again
  244. X *    use the interp token.
  245. X *
  246. X *----------------------------------------------------------------------
  247. X */
  248. X
  249. Xvoid
  250. XTcl_DeleteInterp(interp)
  251. X    Tcl_Interp *interp;        /* Token for command interpreter (returned
  252. X                 * by a previous call to Tcl_CreateInterp). */
  253. X{
  254. X    Interp *iPtr = (Interp *) interp;
  255. X    Tcl_HashEntry *hPtr;
  256. X    Tcl_HashSearch search;
  257. X    register Command *cmdPtr;
  258. X    int i;
  259. X
  260. X    /*
  261. X     * If the interpreter is in use, delay the deletion until later.
  262. X     */
  263. X
  264. X    iPtr->flags |= DELETED;
  265. X    if (iPtr->numLevels != 0) {
  266. X    return;
  267. X    }
  268. X
  269. X    /*
  270. X     * Free up any remaining resources associated with the
  271. X     * interpreter.
  272. X     */
  273. X
  274. X    for (hPtr = Tcl_FirstHashEntry(&iPtr->commandTable, &search);
  275. X        hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
  276. X    cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
  277. X    if (cmdPtr->deleteProc != NULL) { 
  278. X        (*cmdPtr->deleteProc)(cmdPtr->clientData);
  279. X    }
  280. X    ckfree((char *) cmdPtr);
  281. X    }
  282. X    Tcl_DeleteHashTable(&iPtr->commandTable);
  283. X    TclDeleteVars(iPtr, &iPtr->globalTable);
  284. X    if (iPtr->events != NULL) {
  285. X    int i;
  286. X
  287. X    for (i = 0; i < iPtr->numEvents; i++) {
  288. X        ckfree(iPtr->events[i].command);
  289. X    }
  290. X    ckfree((char *) iPtr->events);
  291. X    }
  292. X    while (iPtr->revPtr != NULL) {
  293. X    HistoryRev *nextPtr = iPtr->revPtr->nextPtr;
  294. X
  295. X    ckfree((char *) iPtr->revPtr);
  296. X    iPtr->revPtr = nextPtr;
  297. X    }
  298. X    if (iPtr->appendResult != NULL) {
  299. X    ckfree(iPtr->appendResult);
  300. X    }
  301. X#ifndef TCL_GENERIC_ONLY
  302. X    if (iPtr->numFiles > 0) {
  303. X    for (i = 0; i < iPtr->numFiles; i++) {
  304. X        OpenFile *filePtr;
  305. X    
  306. X        filePtr = iPtr->filePtrArray[i];
  307. X        if (filePtr == NULL) {
  308. X        continue;
  309. X        }
  310. X        if (i >= 3) {
  311. X        fclose(filePtr->f);
  312. X        if (filePtr->f2 != NULL) {
  313. X            fclose(filePtr->f2);
  314. X        }
  315. X        if (filePtr->numPids > 0) {
  316. X            Tcl_DetachPids(filePtr->numPids, filePtr->pidPtr);
  317. X            ckfree((char *) filePtr->pidPtr);
  318. X        }
  319. X        }
  320. X        ckfree((char *) filePtr);
  321. X    }
  322. X    ckfree((char *) iPtr->filePtrArray);
  323. X    }
  324. X#endif
  325. X    for (i = 0; i < NUM_REGEXPS; i++) {
  326. X    if (iPtr->patterns[i] == NULL) {
  327. X        break;
  328. X    }
  329. X    ckfree(iPtr->patterns[i]);
  330. X    ckfree((char *) iPtr->regexps[i]);
  331. X    }
  332. X    while (iPtr->tracePtr != NULL) {
  333. X    Trace *nextPtr = iPtr->tracePtr->nextPtr;
  334. X
  335. X    ckfree((char *) iPtr->tracePtr);
  336. X    iPtr->tracePtr = nextPtr;
  337. X    }
  338. X    ckfree((char *) iPtr);
  339. X}
  340. X
  341. X/*
  342. X *----------------------------------------------------------------------
  343. X *
  344. X * Tcl_CreateCommand --
  345. X *
  346. X *    Define a new command in a command table.
  347. X *
  348. X * Results:
  349. X *    None.
  350. X *
  351. X * Side effects:
  352. X *    If a command named cmdName already exists for interp, it is
  353. X *    deleted.  In the future, when cmdName is seen as the name of
  354. X *    a command by Tcl_Eval, proc will be called.  When the command
  355. X *    is deleted from the table, deleteProc will be called.  See the
  356. X *    manual entry for details on the calling sequence.
  357. X *
  358. X *----------------------------------------------------------------------
  359. X */
  360. X
  361. Xvoid
  362. XTcl_CreateCommand(interp, cmdName, proc, clientData, deleteProc)
  363. X    Tcl_Interp *interp;        /* Token for command interpreter (returned
  364. X                 * by a previous call to Tcl_CreateInterp). */
  365. X    char *cmdName;        /* Name of command. */
  366. X    Tcl_CmdProc *proc;        /* Command procedure to associate with
  367. X                 * cmdName. */
  368. X    ClientData clientData;    /* Arbitrary one-word value to pass to proc. */
  369. X    Tcl_CmdDeleteProc *deleteProc;
  370. X                /* If not NULL, gives a procedure to call when
  371. X                 * this command is deleted. */
  372. X{
  373. X    Interp *iPtr = (Interp *) interp;
  374. X    register Command *cmdPtr;
  375. X    Tcl_HashEntry *hPtr;
  376. X    int new;
  377. X
  378. X    hPtr = Tcl_CreateHashEntry(&iPtr->commandTable, cmdName, &new);
  379. X    if (!new) {
  380. X    /*
  381. X     * Command already exists:  delete the old one.
  382. X     */
  383. X
  384. X    cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
  385. X    if (cmdPtr->deleteProc != NULL) {
  386. X        (*cmdPtr->deleteProc)(cmdPtr->clientData);
  387. X    }
  388. X    } else {
  389. X    cmdPtr = (Command *) ckalloc(sizeof(Command));
  390. X    Tcl_SetHashValue(hPtr, cmdPtr);
  391. X    }
  392. X    cmdPtr->proc = proc;
  393. X    cmdPtr->clientData = clientData;
  394. X    cmdPtr->deleteProc = deleteProc;
  395. X}
  396. X
  397. X/*
  398. X *----------------------------------------------------------------------
  399. X *
  400. X * Tcl_DeleteCommand --
  401. X *
  402. X *    Remove the given command from the given interpreter.
  403. X *
  404. X * Results:
  405. X *    0 is returned if the command was deleted successfully.
  406. X *    -1 is returned if there didn't exist a command by that
  407. X *    name.
  408. X *
  409. X * Side effects:
  410. X *    CmdName will no longer be recognized as a valid command for
  411. X *    interp.
  412. X *
  413. X *----------------------------------------------------------------------
  414. X */
  415. X
  416. Xint
  417. XTcl_DeleteCommand(interp, cmdName)
  418. X    Tcl_Interp *interp;        /* Token for command interpreter (returned
  419. X                 * by a previous call to Tcl_CreateInterp). */
  420. X    char *cmdName;        /* Name of command to remove. */
  421. X{
  422. X    Interp *iPtr = (Interp *) interp;
  423. X    Tcl_HashEntry *hPtr;
  424. X    Command *cmdPtr;
  425. X
  426. X    hPtr = Tcl_FindHashEntry(&iPtr->commandTable, cmdName);
  427. X    if (hPtr == NULL) {
  428. X    return -1;
  429. X    }
  430. X    cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
  431. X    if (cmdPtr->deleteProc != NULL) {
  432. X    (*cmdPtr->deleteProc)(cmdPtr->clientData);
  433. X    }
  434. X    ckfree((char *) cmdPtr);
  435. X    Tcl_DeleteHashEntry(hPtr);
  436. X    return 0;
  437. X}
  438. X
  439. X/*
  440. X *-----------------------------------------------------------------
  441. X *
  442. X * Tcl_Eval --
  443. X *
  444. X *    Parse and execute a command in the Tcl language.
  445. X *
  446. X * Results:
  447. X *    The return value is one of the return codes defined in tcl.hd
  448. X *    (such as TCL_OK), and interp->result contains a string value
  449. X *    to supplement the return code.  The value of interp->result
  450. X *    will persist only until the next call to Tcl_Eval:  copy it or
  451. X *    lose it! *TermPtr is filled in with the character just after
  452. X *    the last one that was part of the command (usually a NULL
  453. X *    character or a closing bracket).
  454. X *
  455. X * Side effects:
  456. X *    Almost certainly;  depends on the command.
  457. X *
  458. X *-----------------------------------------------------------------
  459. X */
  460. X
  461. Xint
  462. XTcl_Eval(interp, cmd, flags, termPtr)
  463. X    Tcl_Interp *interp;        /* Token for command interpreter (returned
  464. X                 * by a previous call to Tcl_CreateInterp). */
  465. X    char *cmd;            /* Pointer to TCL command to interpret. */
  466. X    int flags;            /* OR-ed combination of flags like
  467. X                 * TCL_BRACKET_TERM and TCL_RECORD_BOUNDS. */
  468. X    char **termPtr;        /* If non-NULL, fill in the address it points
  469. X                 * to with the address of the char. just after
  470. X                 * the last one that was part of cmd.  See
  471. X                 * the man page for details on this. */
  472. X{
  473. X    /*
  474. X     * The storage immediately below is used to generate a copy
  475. X     * of the command, after all argument substitutions.  Pv will
  476. X     * contain the argv values passed to the command procedure.
  477. X     */
  478. X
  479. X#   define NUM_CHARS 200
  480. X    char copyStorage[NUM_CHARS];
  481. X    ParseValue pv;
  482. X    char *oldBuffer;
  483. X
  484. X    /*
  485. X     * This procedure generates an (argv, argc) array for the command,
  486. X     * It starts out with stack-allocated space but uses dynamically-
  487. X     * allocated storage to increase it if needed.
  488. X     */
  489. X
  490. X#   define NUM_ARGS 10
  491. X    char *(argStorage[NUM_ARGS]);
  492. X    char **argv = argStorage;
  493. X    int argc;
  494. X    int argSize = NUM_ARGS;
  495. X
  496. X    register char *src;            /* Points to current character
  497. X                     * in cmd. */
  498. X    char termChar;            /* Return when this character is found
  499. X                     * (either ']' or '\0').  Zero means
  500. X                     * that newlines terminate commands. */
  501. X    int result;                /* Return value. */
  502. X    register Interp *iPtr = (Interp *) interp;
  503. X    Tcl_HashEntry *hPtr;
  504. X    Command *cmdPtr;
  505. X    char *dummy;            /* Make termPtr point here if it was
  506. X                     * originally NULL. */
  507. X    char *cmdStart;            /* Points to first non-blank char. in
  508. X                     * command (used in calling trace
  509. X                     * procedures). */
  510. X    char *ellipsis = "";        /* Used in setting errorInfo variable;
  511. X                     * set to "..." to indicate that not
  512. X                     * all of offending command is included
  513. X                     * in errorInfo.  "" means that the
  514. X                     * command is all there. */
  515. X    register Trace *tracePtr;
  516. X
  517. X    /*
  518. X     * Initialize the result to an empty string and clear out any
  519. X     * error information.  This makes sure that we return an empty
  520. X     * result if there are no commands in the command string.
  521. X     */
  522. X
  523. X    Tcl_FreeResult((Tcl_Interp *) iPtr);
  524. X    iPtr->result = iPtr->resultSpace;
  525. X    iPtr->resultSpace[0] = 0;
  526. X    result = TCL_OK;
  527. X
  528. X    /*
  529. X     * Check depth of nested calls to Tcl_Eval:  if this gets too large,
  530. X     * it's probably because of an infinite loop somewhere.
  531. X     */
  532. X
  533. X    iPtr->numLevels++;
  534. X    if (iPtr->numLevels > MAX_NESTING_DEPTH) {
  535. X    iPtr->result =  "too many nested calls to Tcl_Eval (infinite loop?)";
  536. X    return TCL_ERROR;
  537. X    }
  538. X
  539. X    /*
  540. X     * Initialize the area in which command copies will be assembled.
  541. X     */
  542. X
  543. X    pv.buffer = copyStorage;
  544. X    pv.end = copyStorage + NUM_CHARS - 1;
  545. X    pv.expandProc = TclExpandParseValue;
  546. X    pv.clientData = (ClientData) NULL;
  547. X
  548. X    src = cmd;
  549. X    if (flags & TCL_BRACKET_TERM) {
  550. X    termChar = ']';
  551. X    } else {
  552. X    termChar = 0;
  553. X    }
  554. X    if (termPtr == NULL) {
  555. X    termPtr = &dummy;
  556. X    }
  557. X    *termPtr = src;
  558. X    cmdStart = src;
  559. X
  560. X    /*
  561. X     * There can be many sub-commands (separated by semi-colons or
  562. X     * newlines) in one command string.  This outer loop iterates over
  563. X     * individual commands.
  564. X     */
  565. X
  566. X    while (*src != termChar) {
  567. X    iPtr->flags &= ~(ERR_IN_PROGRESS | ERROR_CODE_SET);
  568. X
  569. X    /*
  570. X     * Skim off leading white space and semi-colons, and skip
  571. X     * comments.
  572. X     */
  573. X
  574. X    while (1) {
  575. X        register char c = *src;
  576. X
  577. X        if ((CHAR_TYPE(c) != TCL_SPACE) && (c != ';') && (c != '\n')) {
  578. X        break;
  579. X        }
  580. X        src += 1;
  581. X    }
  582. X    if (*src == '#') {
  583. X        for (src++; *src != 0; src++) {
  584. X        if (*src == '\n') {
  585. X            src++;
  586. X            break;
  587. X        }
  588. X        }
  589. X        continue;
  590. X    }
  591. X    cmdStart = src;
  592. X
  593. X    /*
  594. X     * Parse the words of the command, generating the argc and
  595. X     * argv for the command procedure.  May have to call
  596. X     * TclParseWords several times, expanding the argv array
  597. X     * between calls.
  598. X     */
  599. X
  600. X    pv.next = oldBuffer = pv.buffer;
  601. X    argc = 0;
  602. X    while (1) {
  603. X        int newArgs, maxArgs;
  604. X        char **newArgv;
  605. X        int i;
  606. X
  607. X        /*
  608. X         * Note:  the "- 2" below guarantees that we won't use the
  609. X         * last two argv slots here.  One is for a NULL pointer to
  610. X         * mark the end of the list, and the other is to leave room
  611. X         * for inserting the command name "unknown" as the first
  612. X         * argument (see below).
  613. X         */
  614. X
  615. X        maxArgs = argSize - argc - 2;
  616. X        result = TclParseWords((Tcl_Interp *) iPtr, src, flags,
  617. X            maxArgs, termPtr, &newArgs, &argv[argc], &pv);
  618. X        src = *termPtr;
  619. X        if (result != TCL_OK) {
  620. X        ellipsis = "...";
  621. X        goto done;
  622. X        }
  623. X
  624. X        /*
  625. X         * Careful!  Buffer space may have gotten reallocated while
  626. X         * parsing words.  If this happened, be sure to update all
  627. X         * of the older argv pointers to refer to the new space.
  628. X         */
  629. X
  630. X        if (oldBuffer != pv.buffer) {
  631. X        int i;
  632. X
  633. X        for (i = 0; i < argc; i++) {
  634. X            argv[i] = pv.buffer + (argv[i] - oldBuffer);
  635. X        }
  636. X        oldBuffer = pv.buffer;
  637. X        }
  638. X        argc += newArgs;
  639. X        if (newArgs < maxArgs) {
  640. X        argv[argc] = (char *) NULL;
  641. X        break;
  642. X        }
  643. X
  644. X        /*
  645. X         * Args didn't all fit in the current array.  Make it bigger.
  646. X         */
  647. X
  648. X        argSize *= 2;
  649. X        newArgv = (char **)
  650. X            ckalloc((unsigned) argSize * sizeof(char *));
  651. X        for (i = 0; i < argc; i++) {
  652. X        newArgv[i] = argv[i];
  653. X        }
  654. X        if (argv != argStorage) {
  655. X        ckfree((char *) argv);
  656. X        }
  657. X        argv = newArgv;
  658. X    }
  659. X
  660. X    /*
  661. X     * If this is an empty command (or if we're just parsing
  662. X     * commands without evaluating them), then just skip to the
  663. X     * next command.
  664. X     */
  665. X
  666. X    if ((argc == 0) || iPtr->noEval) {
  667. X        continue;
  668. X    }
  669. X    argv[argc] = NULL;
  670. X
  671. X    /*
  672. X     * Save information for the history module, if needed.
  673. X     */
  674. X
  675. X    if (flags & TCL_RECORD_BOUNDS) {
  676. X        iPtr->evalFirst = cmdStart;
  677. X        iPtr->evalLast = src-1;
  678. X    }
  679. X
  680. X    /*
  681. X     * Find the procedure to execute this command.  If there isn't
  682. X     * one, then see if there is a command "unknown".  If so,
  683. X     * invoke it instead, passing it the words of the original
  684. X     * command as arguments.
  685. X     */
  686. X
  687. X    hPtr = Tcl_FindHashEntry(&iPtr->commandTable, argv[0]);
  688. X    if (hPtr == NULL) {
  689. X        int i;
  690. X
  691. X        hPtr = Tcl_FindHashEntry(&iPtr->commandTable, "unknown");
  692. X        if (hPtr == NULL) {
  693. X        Tcl_ResetResult(interp);
  694. X        Tcl_AppendResult(interp, "invalid command name: \"",
  695. X            argv[0], "\"", (char *) NULL);
  696. X        result = TCL_ERROR;
  697. X        goto done;
  698. X        }
  699. X        for (i = argc; i >= 0; i--) {
  700. X        argv[i+1] = argv[i];
  701. X        }
  702. X        argv[0] = "unknown";
  703. X        argc++;
  704. X    }
  705. X    cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
  706. X
  707. X    /*
  708. X     * Call trace procedures, if any.
  709. X     */
  710. X
  711. X    for (tracePtr = iPtr->tracePtr; tracePtr != NULL;
  712. X        tracePtr = tracePtr->nextPtr) {
  713. X        char saved;
  714. X
  715. X        if (tracePtr->level < iPtr->numLevels) {
  716. X        continue;
  717. X        }
  718. X        saved = *src;
  719. X        *src = 0;
  720. X        (*tracePtr->proc)(tracePtr->clientData, interp, iPtr->numLevels,
  721. X            cmdStart, cmdPtr->proc, cmdPtr->clientData, argc, argv);
  722. X        *src = saved;
  723. X    }
  724. X
  725. X    /*
  726. X     * At long last, invoke the command procedure.  Reset the
  727. X     * result to its default empty value first (it could have
  728. X     * gotten changed by earlier commands in the same command
  729. X     * string).
  730. X     */
  731. X
  732. X    iPtr->cmdCount++;
  733. X    Tcl_FreeResult(iPtr);
  734. X    iPtr->result = iPtr->resultSpace;
  735. X    iPtr->resultSpace[0] = 0;
  736. X    result = (*cmdPtr->proc)(cmdPtr->clientData, interp, argc, argv);
  737. X        /*
  738. X         * Signal handling added for Extended Tcl.
  739. X         */ 
  740. X        result = Tcl_CheckForSignal (interp, result);
  741. X    if (result != TCL_OK) {
  742. X        break;
  743. X    }
  744. X    }
  745. X
  746. X    /*
  747. X     * Free up any extra resources that were allocated.
  748. X     */
  749. X
  750. X    done:
  751. X    if (pv.buffer != copyStorage) {
  752. X    ckfree((char *) pv.buffer);
  753. X    }
  754. X    if (argv != argStorage) {
  755. X    ckfree((char *) argv);
  756. X    }
  757. X    iPtr->numLevels--;
  758. X    if (iPtr->numLevels == 0) {
  759. X    if (result == TCL_RETURN) {
  760. X        result = TCL_OK;
  761. X    }
  762. X    if ((result != TCL_OK) && (result != TCL_ERROR)) {
  763. X        Tcl_ResetResult(interp);
  764. X        if (result == TCL_BREAK) {
  765. X        iPtr->result = "invoked \"break\" outside of a loop";
  766. X        } else if (result == TCL_CONTINUE) {
  767. X        iPtr->result = "invoked \"continue\" outside of a loop";
  768. X        } else {
  769. X        iPtr->result = iPtr->resultSpace;
  770. X        sprintf(iPtr->resultSpace, "command returned bad code: %d",
  771. X            result);
  772. X        }
  773. X        result = TCL_ERROR;
  774. X    }
  775. X    if (iPtr->flags & DELETED) {
  776. X        Tcl_DeleteInterp(interp);
  777. X    }
  778. X    }
  779. X
  780. X    /*
  781. X     * If an error occurred, record information about what was being
  782. X     * executed when the error occurred.
  783. X     */
  784. X
  785. X    if ((result == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) {
  786. X    int numChars;
  787. X    register char *p;
  788. X
  789. X    /*
  790. X     * Compute the line number where the error occurred.
  791. X     */
  792. X
  793. X    iPtr->errorLine = 1;
  794. X    for (p = cmd; p != cmdStart; p++) {
  795. X        if (*p == '\n') {
  796. X        iPtr->errorLine++;
  797. X        }
  798. X    }
  799. X    for ( ; isspace(*p) || (*p == ';'); p++) {
  800. X        if (*p == '\n') {
  801. X        iPtr->errorLine++;
  802. X        }
  803. X    }
  804. X
  805. X    /*
  806. X     * Figure out how much of the command to print in the error
  807. X     * message (up to a certain number of characters, or up to
  808. X     * the first new-line).
  809. X     */
  810. X
  811. X    numChars = src - cmdStart;
  812. X    if (numChars > (NUM_CHARS-50)) {
  813. X        numChars = NUM_CHARS-50;
  814. X        ellipsis = " ...";
  815. X    }
  816. X
  817. X    if (!(iPtr->flags & ERR_IN_PROGRESS)) {
  818. X        sprintf(copyStorage, "\n    while executing\n\"%.*s%s\"",
  819. X            numChars, cmdStart, ellipsis);
  820. X    } else {
  821. X        sprintf(copyStorage, "\n    invoked from within\n\"%.*s%s\"",
  822. X            numChars, cmdStart, ellipsis);
  823. X    }
  824. X    Tcl_AddErrorInfo(interp, copyStorage);
  825. X    iPtr->flags &= ~ERR_ALREADY_LOGGED;
  826. X    } else {
  827. X    iPtr->flags &= ~ERR_ALREADY_LOGGED;
  828. X    }
  829. X    return result;
  830. X}
  831. X
  832. X/*
  833. X *----------------------------------------------------------------------
  834. X *
  835. X * Tcl_CreateTrace --
  836. X *
  837. X *    Arrange for a procedure to be called to trace command execution.
  838. X *
  839. X * Results:
  840. X *    The return value is a token for the trace, which may be passed
  841. X *    to Tcl_DeleteTrace to eliminate the trace.
  842. X *
  843. X * Side effects:
  844. X *    From now on, proc will be called just before a command procedure
  845. X *    is called to execute a Tcl command.  Calls to proc will have the
  846. X *    following form:
  847. X *
  848. X *    void
  849. X *    proc(clientData, interp, level, command, cmdProc, cmdClientData,
  850. X *        argc, argv)
  851. X *        ClientData clientData;
  852. X *        Tcl_Interp *interp;
  853. X *        int level;
  854. X *        char *command;
  855. X *        int (*cmdProc)();
  856. X *        ClientData cmdClientData;
  857. X *        int argc;
  858. X *        char **argv;
  859. X *    {
  860. X *    }
  861. X *
  862. X *    The clientData and interp arguments to proc will be the same
  863. X *    as the corresponding arguments to this procedure.  Level gives
  864. X *    the nesting level of command interpretation for this interpreter
  865. X *    (0 corresponds to top level).  Command gives the ASCII text of
  866. X *    the raw command, cmdProc and cmdClientData give the procedure that
  867. X *    will be called to process the command and the ClientData value it
  868. X *    will receive, and argc and argv give the arguments to the
  869. X *    command, after any argument parsing and substitution.  Proc
  870. X *    does not return a value.
  871. X *
  872. X *----------------------------------------------------------------------
  873. X */
  874. X
  875. XTcl_Trace
  876. XTcl_CreateTrace(interp, level, proc, clientData)
  877. X    Tcl_Interp *interp;        /* Interpreter in which to create the trace. */
  878. X    int level;            /* Only call proc for commands at nesting level
  879. X                 * <= level (1 => top level). */
  880. X    Tcl_CmdTraceProc *proc;    /* Procedure to call before executing each
  881. X                 * command. */
  882. X    ClientData clientData;    /* Arbitrary one-word value to pass to proc. */
  883. X{
  884. X    register Trace *tracePtr;
  885. X    register Interp *iPtr = (Interp *) interp;
  886. X
  887. X    tracePtr = (Trace *) ckalloc(sizeof(Trace));
  888. X    tracePtr->level = level;
  889. X    tracePtr->proc = proc;
  890. X    tracePtr->clientData = clientData;
  891. X    tracePtr->nextPtr = iPtr->tracePtr;
  892. X    iPtr->tracePtr = tracePtr;
  893. X
  894. X    return (Tcl_Trace) tracePtr;
  895. X}
  896. X
  897. X/*
  898. X *----------------------------------------------------------------------
  899. X *
  900. X * Tcl_DeleteTrace --
  901. X *
  902. X *    Remove a trace.
  903. X *
  904. X * Results:
  905. X *    None.
  906. X *
  907. X * Side effects:
  908. X *    From now on there will be no more calls to the procedure given
  909. X *    in trace.
  910. X *
  911. X *----------------------------------------------------------------------
  912. X */
  913. X
  914. Xvoid
  915. XTcl_DeleteTrace(interp, trace)
  916. X    Tcl_Interp *interp;        /* Interpreter that contains trace. */
  917. X    Tcl_Trace trace;        /* Token for trace (returned previously by
  918. X                 * Tcl_CreateTrace). */
  919. X{
  920. X    register Interp *iPtr = (Interp *) interp;
  921. X    register Trace *tracePtr = (Trace *) trace;
  922. X    register Trace *tracePtr2;
  923. X
  924. X    if (iPtr->tracePtr == tracePtr) {
  925. X    iPtr->tracePtr = tracePtr->nextPtr;
  926. X    ckfree((char *) tracePtr);
  927. X    } else {
  928. X    for (tracePtr2 = iPtr->tracePtr; tracePtr2 != NULL;
  929. X        tracePtr2 = tracePtr2->nextPtr) {
  930. X        if (tracePtr2->nextPtr == tracePtr) {
  931. X        tracePtr2->nextPtr = tracePtr->nextPtr;
  932. X        ckfree((char *) tracePtr);
  933. X        return;
  934. X        }
  935. X    }
  936. X    }
  937. X}
  938. X
  939. X/*
  940. X *----------------------------------------------------------------------
  941. X *
  942. X * Tcl_AddErrorInfo --
  943. X *
  944. X *    Add information to a message being accumulated that describes
  945. X *    the current error.
  946. X *
  947. X * Results:
  948. X *    None.
  949. X *
  950. X * Side effects:
  951. X *    The contents of message are added to the "errorInfo" variable.
  952. X *    If Tcl_Eval has been called since the current value of errorInfo
  953. X *    was set, errorInfo is cleared before adding the new message.
  954. X *
  955. X *----------------------------------------------------------------------
  956. X */
  957. X
  958. Xvoid
  959. XTcl_AddErrorInfo(interp, message)
  960. X    Tcl_Interp *interp;        /* Interpreter to which error information
  961. X                 * pertains. */
  962. X    char *message;        /* Message to record. */
  963. X{
  964. X    register Interp *iPtr = (Interp *) interp;
  965. X
  966. X    /*
  967. X     * If an error is already being logged, then the new errorInfo
  968. X     * is the concatenation of the old info and the new message.
  969. X     * If this is the first piece of info for the error, then the
  970. X     * new errorInfo is the concatenation of the message in
  971. X     * interp->result and the new message.
  972. X     */
  973. X
  974. X    if (!(iPtr->flags & ERR_IN_PROGRESS)) {
  975. X    Tcl_SetVar2(interp, "errorInfo", (char *) NULL, interp->result,
  976. X        TCL_GLOBAL_ONLY);
  977. X    iPtr->flags |= ERR_IN_PROGRESS;
  978. X
  979. X    /*
  980. X     * If the errorCode variable wasn't set by the code that generated
  981. X     * the error, set it to "NONE".
  982. X     */
  983. X
  984. X    if (!(iPtr->flags & ERROR_CODE_SET)) {
  985. X        (void) Tcl_SetVar2(interp, "errorCode", (char *) NULL, "NONE",
  986. X            TCL_GLOBAL_ONLY);
  987. X    }
  988. X    }
  989. X    Tcl_SetVar2(interp, "errorInfo", (char *) NULL, message,
  990. X        TCL_GLOBAL_ONLY|TCL_APPEND_VALUE);
  991. X}
  992. X
  993. X/*
  994. X *----------------------------------------------------------------------
  995. X *
  996. X * Tcl_VarEval --
  997. X *
  998. X *    Given a variable number of string arguments, concatenate them
  999. X *    all together and execute the result as a Tcl command.
  1000. X *
  1001. X * Results:
  1002. X *    A standard Tcl return result.  An error message or other
  1003. X *    result may be left in interp->result.
  1004. X *
  1005. X * Side effects:
  1006. X *    Depends on what was done by the command.
  1007. X *
  1008. X *----------------------------------------------------------------------
  1009. X */
  1010. X    /* VARARGS2 */ /* ARGSUSED */
  1011. Xint
  1012. X#ifndef lint
  1013. XTcl_VarEval(va_alist)
  1014. X#else
  1015. XTcl_VarEval(interp, p, va_alist)
  1016. X    Tcl_Interp *interp;        /* Interpreter in which to execute command. */
  1017. X    char *p;            /* One or more strings to concatenate,
  1018. X                 * terminated with a NULL string. */
  1019. X#endif
  1020. X    va_dcl
  1021. X{
  1022. X    va_list argList;
  1023. X#define FIXED_SIZE 200
  1024. X    char fixedSpace[FIXED_SIZE+1];
  1025. X    int spaceAvl, spaceUsed, length;
  1026. X    char *string, *cmd;
  1027. X    Tcl_Interp *interp;
  1028. X    int result;
  1029. X
  1030. X    /*
  1031. X     * Copy the strings one after the other into a single larger
  1032. X     * string.  Use stack-allocated space for small commands, but if
  1033. X     * the commands gets too large than call ckalloc to create the
  1034. X     * space.
  1035. X     */
  1036. X
  1037. X    va_start(argList);
  1038. X    interp = va_arg(argList, Tcl_Interp *);
  1039. X    spaceAvl = FIXED_SIZE;
  1040. X    spaceUsed = 0;
  1041. X    cmd = fixedSpace;
  1042. X    while (1) {
  1043. X    string = va_arg(argList, char *);
  1044. X    if (string == NULL) {
  1045. X        break;
  1046. X    }
  1047. X    length = strlen(string);
  1048. X    if ((spaceUsed + length) > spaceAvl) {
  1049. X        char *new;
  1050. X
  1051. X        spaceAvl = spaceUsed + length;
  1052. X        spaceAvl += spaceAvl/2;
  1053. X        new = ckalloc((unsigned) spaceAvl);
  1054. X        memcpy((VOID *) new, (VOID *) cmd, spaceUsed);
  1055. X        if (cmd != fixedSpace) {
  1056. X        ckfree(cmd);
  1057. X        }
  1058. X        cmd = new;
  1059. X    }
  1060. X    strcpy(cmd + spaceUsed, string);
  1061. X    spaceUsed += length;
  1062. X    }
  1063. X    va_end(argList);
  1064. X    cmd[spaceUsed] = '\0';
  1065. X
  1066. X    result = Tcl_Eval(interp, cmd, 0, (char **) NULL);
  1067. X    if (cmd != fixedSpace) {
  1068. X    ckfree(cmd);
  1069. X    }
  1070. X    return result;
  1071. X}
  1072. END_OF_FILE
  1073. if test 27787 -ne `wc -c <'extended/ucbsrc/tclBasic.c'`; then
  1074.     echo shar: \"'extended/ucbsrc/tclBasic.c'\" unpacked with wrong size!
  1075. fi
  1076. # end of 'extended/ucbsrc/tclBasic.c'
  1077. fi
  1078. echo shar: End of archive 21 \(of 23\).
  1079. cp /dev/null ark21isdone
  1080. MISSING=""
  1081. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ; do
  1082.     if test ! -f ark${I}isdone ; then
  1083.     MISSING="${MISSING} ${I}"
  1084.     fi
  1085. done
  1086. if test "${MISSING}" = "" ; then
  1087.     echo You have unpacked all 23 archives.
  1088.     echo "Now cd to "extended", edit the makefile, then do a "make""
  1089.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1090. else
  1091.     echo You still need to unpack the following archives:
  1092.     echo "        " ${MISSING}
  1093. fi
  1094. ##  End of shell archive.
  1095. exit 0
  1096.  
  1097. exit 0 # Just in case...
  1098. -- 
  1099. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1100. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1101. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1102. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1103.